//
//  MenuAnimator.mm
//  Imp
//
//  Created by Alex Carter on 11/06/09.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "KFAnimationHelper.h"
#import "KFAnimationState.h"
#import "KFAnimationInfo.h"

#import <QuartzCore/QuartzCore.h>

#ifndef DEGREES_TO_RADIANS
#define DEGREES_TO_RADIANS(__DEG__) ((__DEG__) * 0.0174532925f)
#endif

#ifndef RADIANS_TO_DEGREES
#define RADIANS_TO_DEGREES(__RAD__) ((__RAD__) * 57.2957795f)
#endif

#define CENTER_POINT CGPointMake(650,160)

#define ROTATION_TIME 0.3

@interface KFAnimationHelper () 


-(void) initializeStates;


-(void) assignAnimation:(CAAnimation*) theAnimation fromState:(KFAnimationState*)beginState toState:(KFAnimationState*)endState toView:(KFView*)theView;
-(KFAnimationState*) stateFromView:(KFView*) theView;
-(CAAnimation*) animationFromState:(KFAnimationState*) startState toState:(KFAnimationState*) endState;


-(NSInteger) transformIndex:(NSInteger) theIndex;


@end



@implementation KFAnimationHelper
@synthesize animatingIn;
@synthesize animatingOut;
@synthesize animatingRotate;
@synthesize animationInfo;

@synthesize states;
@synthesize delegate;
@synthesize visibleViews;
@synthesize hiddenViews;

+(KFAnimationHelper*) animationHelper
{
    return [[[KFAnimationHelper alloc] init] autorelease];
}


- (id) init
{
    self = [super init];
    if (self != nil) {
        
        self.animatingIn = [NSMutableArray array];
        self.animatingOut = [NSMutableArray array]; 
        self.animatingRotate = [NSMutableArray array]; 
        self.animationInfo = [NSMutableDictionary dictionary];
        self.states = [NSMutableArray array];
        self.visibleViews = [NSMutableArray array];
        hiddenViews = [[NSMutableArray alloc] init];  
    
        [self initializeStates];
    }
    return self;
}


-(void) initializeStates
{
   
    {   // state 0
        KFAnimationState * state = [[[KFAnimationState alloc] init] autorelease];
        state.enabled = NO;
        state.position = CGPointMake(100,100);
         state.transform = CGAffineTransformConcat(
         CGAffineTransformConcat(
         CGAffineTransformMakeScale(0.4,0.4), 
         CGAffineTransformMakeTranslation(-300, 0) ),
         CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(20))
         ); 
                 
        [self.states addObject:state];
    }
        
    {   // state 1
        KFAnimationState * state = [[[KFAnimationState alloc] init] autorelease];
        state.enabled = NO;
        state.position = CGPointMake(100,120);
        state.transform = CGAffineTransformConcat(
                                                 CGAffineTransformConcat(
                                                                         CGAffineTransformMakeScale(0.6,0.6), 
                                                                         CGAffineTransformMakeTranslation(-320, 0) ),      
                                                 CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(10))
                                                 );
        [self.states addObject:state];
    }
    
    {   // state 2
        KFAnimationState * state = [[[KFAnimationState alloc] init] autorelease];
        state.enabled = YES;
        state.position = CGPointMake(100,140);
        state.transform =  CGAffineTransformConcat(
                                                  CGAffineTransformMakeTranslation(-340, 0),
                                                  CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0))
                                                  );   
        
        [self.states addObject:state];
    }
    
    {   // state 0
        KFAnimationState *state = [[[KFAnimationState alloc] init] autorelease];
        state.enabled = NO;
        state.position = CGPointMake(100,160);
        state.transform = CGAffineTransformConcat(
                                                 CGAffineTransformConcat(
                                                                         CGAffineTransformMakeScale(0.6,0.6), 
                                                                         CGAffineTransformMakeTranslation(-320, 0) ),
                                                 CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-10))
                                                 ); 
        [self.states addObject:state];
    }
    
    {
        KFAnimationState *state = [[[KFAnimationState alloc] init] autorelease];
        state.enabled = NO;
        state.position = CGPointMake(100,180);
        state.transform = CGAffineTransformConcat(
                                                 CGAffineTransformConcat(
                                                                         CGAffineTransformMakeScale(0.4,0.4), 
                                                                         CGAffineTransformMakeTranslation(-300, 0) ),
                                                 CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(-20))
                                                 ); 
        [self.states addObject:state];
    }
    
    {   // state -1
        KFAnimationState * state = [[[KFAnimationState alloc] init] autorelease];
        state.enabled = NO;  
        state.position = CGPointMake(100,200);       
        state.transform = CGAffineTransformConcat(
                                                 CGAffineTransformConcat(
                                                                         CGAffineTransformMakeScale(0.2,0.2), 
                                                                         CGAffineTransformMakeTranslation(0, 0) ),
                                                 CGAffineTransformMakeRotation(DEGREES_TO_RADIANS(0))
                                                 ); 
        
        [self.states addObject:state];
    }
    
}


-(NSInteger) transformIndex:(NSInteger) theIndex
{
    NSInteger tc = ( [states count] -  [self.visibleViews count] ) / 2;
    return (theIndex + tc) % [states count];
    
}

-(KFAnimationState*) stateAtIndex:(NSInteger) theIndex
{
    return (KFAnimationState*)[self.states objectAtIndex:theIndex];
}

-(void) setState:(KFAnimationState*)theState atIndex:(NSInteger) theIndex
{
    [self.states replaceObjectAtIndex:theIndex withObject:theState];
}

-(void) addView:(KFView*)theView
{
    if(! ( [self.hiddenViews containsObject:theView] || 
           [self.visibleViews containsObject:theView] ) )
    {
      
        //theView.center = CENTER_POINT;        
        [self.hiddenViews addObject:theView];        
    }    
}


-(void) animateAllIn
{
    NSMutableArray *ViewsToShow = [NSMutableArray array];
    int visibleViewCount = [visibleViews count];
    
    // if there is room add any Views that can fit to the visible array
    while ( [hiddenViews count]  > 0 && visibleViewCount < [states count] )
    {
        [ViewsToShow addObject:[hiddenViews objectAtIndex:0]];
        [visibleViews addObject:[hiddenViews objectAtIndex:0]];
        [hiddenViews removeObjectAtIndex:0];
        visibleViewCount++;
    }   
    
    if(visibleViewCount > 0)
    {
        
        NSEnumerator *e = [visibleViews objectEnumerator];
        KFView* view;
        int i = 0;     
        while (view = [e nextObject])
        {
            // animate in
            
            KFAnimationState* beginState = [self stateAtIndex:0];
            KFAnimationState* endState = [self stateAtIndex:i];
            
            CAAnimation *anim = [self animationFromState:beginState toState:endState];            
            [self assignAnimation:anim fromState:beginState toState:endState toView:view];
                
            i++;
        }
    }
    else
    {
        [self animateAllInDidFinish];
    }
    
}

-(void) animateAllInDidFinish
{ 
    if( [self.delegate respondsToSelector:@selector(animateAllInDidFinish)] )
    {
        [self.delegate animateAllInDidFinish];
    }    
}

-(void) animateAllOut
{
    /*if( [visibleViews count] > 0 )
    {
        NSEnumerator *e = [visibleViews objectEnumerator];
        KFView* View;
        int i = 0;
        while (View = [e nextObject])
        {
            [self animateView:View fromState:i];    
            [hiddenViews addObject:View];
            i++;
        }    
        [visibleViews removeAllObjects];    
    }
    else
    {
        [self animateAllOutDidFinish];
    }
     */
}

-(void) animateAllOutDidFinish
{
    
    if( [self.delegate respondsToSelector:@selector(animateAllOutDidFinish)] )
    {
        [self.delegate animateAllOutDidFinish];
    }
}

// New stuff /////////////////////////////////////////////////////////////////////////////////////////////

-(void) beginRotate
{
    // get the current state for all animateable views
    // save it as the anchor state
    
}


-(void) rotateWithVelocity:(CGFloat) velocity
{
    
}

-(void) rotateBy:(CGFloat) amount
{
    NSLog(@"Rotate value = %f",amount);
    
    // get the diretion from the sign of the rotate amount
    // for each view
    //      rotate it to the next state by the indicated amount
    //      amount should be between 0 and 1. 
    //      if - amount is 1 then set the anchor to the new position
    //
    
    
}

-(void) endRotate
{
    /// finish the animation to the nerest state
}

-(KFAnimationState*) stateFromView:(KFView*) theView
{    
    KFAnimationState *state = [[[KFAnimationState alloc] init] autorelease];
    
    state.transform = theView.layer.affineTransform;
    
    if( [theView respondsToSelector:@selector(enabled)] )
    {
        state.enabled = [(id)theView enabled];
    }    
    
    return state;
    
}

-(CAAnimation*) animationFromState:(KFAnimationState*) startState toState:(KFAnimationState*) endState
{                              
    CABasicAnimation* animTrans = [CABasicAnimation animationWithKeyPath:@"transform"];   

    animTrans.autoreverses=NO;    
    
    CATransform3D t = CATransform3DMakeAffineTransform(startState.transform);    
    animTrans.fromValue = [NSValue valueWithCATransform3D:t];
    
    t = CATransform3DMakeAffineTransform(endState.transform); 
    animTrans.toValue = [NSValue valueWithCATransform3D:t];

    
    CABasicAnimation* animMove = [CABasicAnimation animationWithKeyPath:@"position"];      
    animMove.autoreverses=NO;        
    animMove.fromValue = [NSValue valueWithPoint: NSPointFromCGPoint(startState.position) ];  
    animMove.toValue = [NSValue valueWithPoint: NSPointFromCGPoint(endState.position) ];
    
    
     CABasicAnimation* animFade = [CABasicAnimation animationWithKeyPath:@"opacity"];   

     animFade.autoreverses=NO;    
     animFade.fromValue = [NSNumber numberWithFloat:0.0];
     animFade.toValue = [NSNumber numberWithFloat:1.0];    
    
    CAAnimationGroup *anim = [CAAnimationGroup animation];
    anim.animations=[NSArray arrayWithObjects:animMove,animFade,nil];
    anim.duration=ROTATION_TIME;
    return anim;    
}


- (void)animationDidStart:(CAAnimation *)theAnimation
{
    KFAnimationInfo *info = [self.animationInfo objectForKey:[NSNumber numberWithInt:[theAnimation hash]]];
    if(info != nil)
    {
        info.beginTime = CFAbsoluteTimeGetCurrent(); 
        KFView *view = (KFView*) info.actor;
                        
        //view.layer.affineTransform = info.endState.transform;
        view.layer.position = info.endState.position;
        if( [view respondsToSelector:@selector(setEnabled:)] )
        {
            [(id)view setEnabled:info.endState.enabled];  
        }

    }    
}

- (void)animationDidStop:(CAAnimation *)theAnimation finished:(BOOL)flag
{    
    KFAnimationInfo *info = [self.animationInfo objectForKey:[NSNumber numberWithInt:[theAnimation hash]]];
    if(info != nil)
    {
        info.endTime = CFAbsoluteTimeGetCurrent(); 
        
        if(flag) // the animation is done 
        {
            [self.animationInfo removeObjectForKey:[NSNumber numberWithInt:[theAnimation hash]]];
        }
    }    
}

-(void) assignAnimation:(CAAnimation*) theAnimation fromState:(KFAnimationState*)beginState toState:(KFAnimationState*)endState toView:(KFView*)theView
{
    theAnimation.delegate = self;
    
    NSString *animationKey = [NSString stringWithFormat:@"%d",[theAnimation hash]];
    CALayer *layer = theView.layer;
    [layer addAnimation:theAnimation forKey:animationKey];        
    theAnimation = [layer animationForKey:animationKey];
    
    KFAnimationInfo* animInfo = [KFAnimationInfo animationInfoWithAnimation:theAnimation andActor:theView];
    animInfo.beginState = beginState;
    animInfo.endState = endState;
    
    [self.animationInfo setObject:animInfo forKey:[NSNumber numberWithInt:[theAnimation hash]]];
    
}

- (void) dealloc
{
    
    self.animatingIn = nil;
    self.animatingOut = nil;
    self.animatingRotate = nil;
    self.animationInfo = nil;
    self.states = nil;
    self.visibleViews = nil;
    [hiddenViews release];
    
    [super dealloc];
}

@end





















